namespace Dapper.FastCrud.SqlBuilders.Dialects
{
    using Dapper.FastCrud.EntityDescriptors;
    using Dapper.FastCrud.Mappings.Registrations;
    using System;

    /// <summary>
    /// Statement builder for the <seealso cref="SqlDialect.MySql"/>.
    /// </summary>
    internal class MySqlBuilder : GenericStatementSqlBuilder
    {
        public MySqlBuilder(EntityDescriptor entityDescriptor, EntityRegistration entityMapping)
            : base(entityDescriptor, entityMapping, SqlDialect.MySql)
        {
        }

        /// <summary>
        /// Constructs a full insert statement
        /// </summary>
        protected override string ConstructFullInsertStatementInternal()
        {
            FormattableString sql = $"INSERT INTO {this.GetTableName()} ({this.ConstructColumnEnumerationForInsert()}) VALUES ({this.ConstructParamEnumerationForInsert()}); ";

            if (this.RefreshOnInsertProperties.Length > 0)
            {
                // we have to bring some column values back
                if (this.KeyProperties.Length == 0)
                {
                    throw new NotSupportedException($"Entity '{this.EntityRegistration.EntityType.Name}' has database generated fields but no primary key to retrieve them with after insertion.");
                }

                // we have an identity column, so we can fetch the rest of them
                if (this.InsertKeyDatabaseGeneratedProperties.Length == 1 && this.RefreshOnInsertProperties.Length == 1)
                {
                    // just one, this is going to be easy
                    sql = $"{sql} SELECT LAST_INSERT_ID() as {this.GetDelimitedIdentifier(this.InsertKeyDatabaseGeneratedProperties[0].PropertyName)}";
                }
                else
                {
                    // There are no primary keys generated by the database
                    if (this.InsertKeyDatabaseGeneratedProperties.Length == 0)
                    {
                        sql = $"{sql} SELECT {this.ConstructRefreshOnInsertColumnSelection()} FROM {this.GetTableName()} WHERE {this.ConstructKeysWhereClause()}";
                    }
                    else
                    {
                        sql = $"{sql} SELECT {this.ConstructRefreshOnInsertColumnSelection()} FROM {this.GetTableName()} WHERE {this.GetColumnName(this.InsertKeyDatabaseGeneratedProperties[0], null, false)} = LAST_INSERT_ID()";
                    }
                }
            }

            return FormattableString.Invariant(sql);
        }

        protected override string ConstructFullSelectStatementInternal(
            string selectClause,
            string fromClause,
            string? whereClause = null,
            string? orderClause = null,
            long? skipRowsCount = null,
            long? limitRowsCount = null)
        {
            FormattableString sql = $"SELECT {selectClause} FROM {fromClause}";

            if (whereClause != null)
            {
                sql = $"{sql} WHERE {whereClause}";
            }

            if (orderClause != null)
            {
                sql = $"{sql} ORDER BY {orderClause}";
            }

            if (skipRowsCount.HasValue)
            {
                sql = $"{sql} LIMIT {skipRowsCount},{limitRowsCount ?? (int?)int.MaxValue}";
            }
            else if (limitRowsCount.HasValue)
            {
                sql = $"{sql} LIMIT {limitRowsCount}";
            }

            return FormattableString.Invariant(sql);
        }
    }
}
